#include "config.h"
#include <string.h>

#include "xIPC.h"
#include "aux_types.h"
#include "aux_errno.h"
#include "aux_debugmsg.h"
#include "aux_thread.h"
#include "aux_messagemanager.h"
#include "aux_time.h"
#include "aux_message.h"
#include "aux_idmanager.h"
#include "aux_datacheck.h"
#include "aux_string.h"
#include "aux_package.h"


/*
typedef {
    u32 nPackageInfoSize;
    u32 nDataChkResult;
    u32 nDataByteCnt;
} TxIPCMsgPackageInfo;
typedef {
    u32 nStartFlag;  //FIX 0xA5
    TxIPCMsgPackageInfo tInfo;
    u32 nEndFlag;    //FIX 0x5A
} TxIPCMsgPackageHeader;
*/
enum
{
    START_FLAG_OFFSET = 0,
    INFO_SIZE_OFFSET = 4,
    DATA_CHECK_RESULT_OFFSET = 8,
    DATA_BYTE_CNT_OFFSET = 12,
    END_FLAG_OFFSET = 16,
    TAIL_AFTER_HEADER_OFFSET = 20,
    DATA_BUFFER_BEGIN_OFFSET = 20,
    PACKAGE_HEADER_SIZE = 20
};

EErrNo xIPC_Pkg_ChkHeaderIgnoreData(u8 *pbyHeaderBegin, u32 nByteCnt)
{
    u32 *pnData;

    if (!pbyHeaderBegin)
        return -ERRNO_EPARAMETER_INVALID;

    if (0 == nByteCnt)
        return ERRNO_NOTFIND;

    if (nByteCnt < PACKAGE_HEADER_SIZE) /* sizeof(TxIPCMsgPackageHeader) */
    {
        if (nByteCnt >= START_FLAG_OFFSET + sizeof(u32))
        {
            pnData = (u32 *)(pbyHeaderBegin + START_FLAG_OFFSET);
            if (*pnData != MESSAGE_PACKAGE_HEADER_START_FLAG)
                return -ERRNO_EWRONG;
        }

        if (nByteCnt >= INFO_SIZE_OFFSET + sizeof(u32))
        {
            pnData = (u32 *)(pbyHeaderBegin + INFO_SIZE_OFFSET);
            if (*pnData != PACKAGE_HEADER_SIZE) //sizeof(TxIPCMsgPackageInfo)
                return -ERRNO_EWRONG;
        }

        if (nByteCnt >= END_FLAG_OFFSET + sizeof(u32))
        {
            pnData = (u32 *)(pbyHeaderBegin + END_FLAG_OFFSET);
            if (*pnData != MESSAGE_PACKAGE_HEADER_END_FLAG) //sizeof(TxIPCMsgPackageInfo)
                return -ERRNO_EWRONG;
        }

        return ERRNO_INCOMPLETE;
    }

    pnData = (u32 *)(pbyHeaderBegin + START_FLAG_OFFSET);
    if (*pnData != MESSAGE_PACKAGE_HEADER_START_FLAG)
        return -ERRNO_EWRONG;

    pnData = (u32 *)(pbyHeaderBegin + INFO_SIZE_OFFSET);
    if (*pnData != PACKAGE_HEADER_SIZE) //sizeof(TxIPCMsgPackageInfo)
        return -ERRNO_EWRONG;

    pnData = (u32 *)(pbyHeaderBegin + END_FLAG_OFFSET);
    if (*pnData != MESSAGE_PACKAGE_HEADER_END_FLAG) //sizeof(TxIPCMsgPackageInfo)
        return -ERRNO_EWRONG;

    return ERRNO_VALID;
}

EErrNo xIPC_Pkg_GetPkgSize(u8 *pbyHeaderBegin,
                                            u32 nByteCnt, u32 *pnSize)
{
    u32   *pnData;
    EErrNo eRet;

    if (!pbyHeaderBegin || !nByteCnt || !pnSize)
        return -ERRNO_EPARAMETER_INVALID;

    eRet = xIPC_Pkg_ChkHeaderIgnoreData(pbyHeaderBegin, nByteCnt);

    if (ERRNO_INCOMPLETE == eRet)
        return ERRNO_INCOMPLETE;

    if (ERRNO_VALID != eRet)
        return -ERRNO_EWRONG;

    pnData  = (u32 *)(pbyHeaderBegin + DATA_BYTE_CNT_OFFSET);
    *pnSize = (*pnData) + PACKAGE_HEADER_SIZE; /* msg data size + header size */

    return ERRNO_SUCCESS;
}

EErrNo xIPC_Pkg_GetMsgPointer(u8 *pbyHeaderBegin,
                                       u32 nByteCnt, u8 **ppbyData, u32 *pnSize)
{
    u32   *pnData;
    EErrNo eRet;

    if (!pbyHeaderBegin || !nByteCnt || !pnSize || !ppbyData)
        return -ERRNO_EPARAMETER_INVALID;

    eRet = xIPC_Pkg_ChkHeaderIgnoreData(pbyHeaderBegin, nByteCnt);
    if (ERRNO_INCOMPLETE == eRet)
        return ERRNO_INCOMPLETE;

    if (ERRNO_VALID != eRet)
        return -ERRNO_EWRONG;

    *ppbyData = (u8 *)(pbyHeaderBegin + TAIL_AFTER_HEADER_OFFSET);
    pnData    = (u32 *)(pbyHeaderBegin + DATA_BYTE_CNT_OFFSET);
    *pnSize   = (*pnData); /* msg data size */
    return ERRNO_SUCCESS;
}

EErrNo xIPCCheckMessagePackageValid(u8 *pbyHeaderBegin, u32 nByteCnt)
{
    u32 *pnData;
    u8  *pbyMsgData;
    u32  nMsgDataLen = 0;
    u32  nPackageSize;
    EErrNo eRet;

    u32  nDataChkRet;

    eRet = xIPC_Pkg_ChkHeaderIgnoreData(pbyHeaderBegin, nByteCnt);
    if (ERRNO_INCOMPLETE == eRet)
        return ERRNO_INCOMPLETE;

    if (ERRNO_VALID != eRet)
        return -ERRNO_EWRONG;

    eRet = xIPC_Pkg_GetPkgSize(pbyHeaderBegin, nByteCnt, &nPackageSize);
    if (ERRNO_INCOMPLETE == eRet)
        return ERRNO_INCOMPLETE;

    if (ERRNO_SUCCESS != eRet)
        return -ERRNO_EWRONG;

    if (nPackageSize > nByteCnt)
        return ERRNO_INCOMPLETE;

    pnData = (u32 *)(pbyHeaderBegin + DATA_CHECK_RESULT_OFFSET);
    nDataChkRet = *pnData;

    pnData = (u32 *)(pbyHeaderBegin + DATA_BYTE_CNT_OFFSET);
    nMsgDataLen = *pnData;

    pbyMsgData = (u8 *)(pbyHeaderBegin + DATA_BUFFER_BEGIN_OFFSET);

    if (ERRNO_SUCCESS != xIPCDataCheckDataValid(pbyMsgData, nMsgDataLen, nDataChkRet))
        return -ERRNO_EWRONG;
    else
        return ERRNO_VALID;
}

EErrNo xIPCPackageFindMessageHeader(u8 *pbyHeaderBegin,
                                                 u32 nByteCnt, u32 *pnOffset)
{
    u32 nOffset = 0;
    EErrNo eRet;

    if (!pbyHeaderBegin || !nByteCnt || !pnOffset)
        return -ERRNO_EPARAMETER_INVALID;

    while (nOffset <= nByteCnt)
    {
        eRet = xIPC_Pkg_ChkHeaderIgnoreData(pbyHeaderBegin + nOffset,
                                                nByteCnt - nOffset);
        if (ERRNO_VALID == eRet)
        {
            *pnOffset = nOffset;
            return ERRNO_SUCCESS;
        }
        else if (ERRNO_INCOMPLETE == eRet)
        {
            *pnOffset = nOffset;
            return ERRNO_INCOMPLETE;
        }

        nOffset++;
    }

    *pnOffset = nOffset;
    return ERRNO_FAIL;
}

/*
 * find the next mesg, verify the header and the body of mesg
 */
EErrNo xIPCPackageFindNextPackageAndChk(u8 *pbyHeaderBegin,
                                           u32 nByteCnt, u32 *pnOffset)
{
    u32 nOffset = 0;
    EErrNo eRet;

    if (!pbyHeaderBegin || !nByteCnt || !pnOffset)
        return -ERRNO_EPARAMETER_INVALID;

    eRet = xIPCPackageFindMessageHeader(pbyHeaderBegin, nByteCnt, &nOffset);
    *pnOffset = nOffset;

    if (ERRNO_INCOMPLETE == eRet)
    {
        return ERRNO_INCOMPLETE;
    }

    if (ERRNO_SUCCESS == eRet)
    {
        eRet = xIPCCheckMessagePackageValid(pbyHeaderBegin + nOffset,
                                            nByteCnt - nOffset);
        if (ERRNO_INCOMPLETE == eRet)
        {
            return ERRNO_INCOMPLETE;
        }
        else if (ERRNO_VALID == eRet)
        {
            return ERRNO_SUCCESS;
        }
        else
        {
            return ERRNO_FAIL;
        }
    }
    else
    {
        return ERRNO_FAIL;
    }
}

/*
 * get the next valid mesg, its header and body is verified OK
 */
EErrNo xIPC_Pkg_FindNextValidPkg(u8 *pbyHeaderBegin,
                                                    u32 nByteCnt, u32 *pnOffset)
{
    u32    nOffset = 0;
    EErrNo eRet;

    if (!pbyHeaderBegin || !pnOffset)
        return -ERRNO_EPARAMETER_INVALID;

    if (!nByteCnt)
        return ERRNO_NOTEXIST;

    while (nOffset < nByteCnt)
    {
        eRet = xIPCPackageFindNextPackageAndChk(pbyHeaderBegin + nOffset,
                                          nByteCnt - nOffset, &nOffset);
        if (ERRNO_SUCCESS == eRet)
        {
            *pnOffset = nOffset;
            return ERRNO_SUCCESS;
        }
        else if (ERRNO_INCOMPLETE == eRet)
        {
            *pnOffset = nOffset;
            return ERRNO_INCOMPLETE;
        }

        nOffset++;
    }

    *pnOffset = nByteCnt;
    return ERRNO_NOTEXIST;
}

/*
 * get the data size of the verified-OK mesg
 */
static EErrNo xIPC_Pkg_GetNextValidMsgSize(u8 *pbyHeaderBegin,
                                              u32 nByteCnt,
                                              u32 *pnOffset, /* header offset */
                                              u32 *pnSize)
{
    u32    nOffset = 0;

    if (!pbyHeaderBegin || !nByteCnt || !pnOffset || !pnSize)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS == xIPC_Pkg_FindNextValidPkg(pbyHeaderBegin,
                                                         nByteCnt,
                                                         pnOffset))
    {
        *pnSize = *((u32 *)(pbyHeaderBegin + *pnOffset + DATA_BYTE_CNT_OFFSET));
        return ERRNO_SUCCESS;
    }

    return ERRNO_FAIL;
}

/*
 * skip the near verified-OK mesg body, return the offset
 * if not find, the offset is the end
 */
EErrNo xIPCPackageSkipCurrentMsg(u8 *pbyHeaderBegin,
                                           u32 nByteCnt, u32 *pnOffset)
{
    u32 nOffset = 0;
    u32 nSize;

    if (!pbyHeaderBegin || !nByteCnt || !pnOffset)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS == xIPC_Pkg_GetNextValidMsgSize(pbyHeaderBegin,
                                            nByteCnt, &nOffset, &nSize))
    {
        *pnOffset = nOffset + nSize;
        return ERRNO_SUCCESS;
    }
    else
    {
        *pnOffset = nByteCnt;
        return ERRNO_FAIL;
    }
}


EErrNo xIPCPackageGetMsg(u8 *pbyHeaderBegin,
                               u32 nByteCnt,  /* IN bytes of buffer data */
                               u32 *pnOffset, /* OUT return the offset */
                               u8  *pbyMsgBuffer,
                               u32 *pnBufferSize) /* IN buffer size, OUT msg size */
{
    u8    *pbyMsg;
    u32    nMsgSize;

    if (!pbyHeaderBegin || !pnOffset ||!pbyMsgBuffer || !pnBufferSize)
        return -ERRNO_EPARAMETER_INVALID;

    if (ERRNO_SUCCESS == xIPC_Pkg_GetNextValidMsgSize(pbyHeaderBegin,
                                                        nByteCnt,
                                                        pnOffset,
                                                        &nMsgSize))
    {
        if (*pnBufferSize < nMsgSize)
        {
            return ERRNO_MEMORYNOTENOUGH;
        }

        if (ERRNO_SUCCESS !=
            xIPC_Pkg_GetMsgPointer(pbyHeaderBegin + (*pnOffset),
                                         nByteCnt - (*pnOffset),
                                         &pbyMsg,
                                         &nMsgSize))
            return ERRNO_FAIL;

        memcpy(pbyMsgBuffer, pbyMsg, nMsgSize);
        *pnBufferSize = nMsgSize;
        return ERRNO_SUCCESS;
    }
    else
    {
        return ERRNO_FAIL;
    }
}

/* cooperate with xIPCPackagePutPackMsg */
EErrNo xIPCPackageGetPackMsgAuto(u8 *pabyData, u32 *pnSize, u8 **ppabyPack)
{
    u8  *pabyDataBuffer = NULL;
    u32 *pnData;
    u32  nCrcRet;

    if (!pabyData || !pnSize || !ppabyPack)
        return -ERRNO_EPARAMETER_INVALID;

    *ppabyPack = NULL;

    pabyDataBuffer = (u8 *)malloc(PACKAGE_HEADER_SIZE + (*pnSize));

    if (!pabyDataBuffer)
        return -ERRNO_EMALLOC_FAIL;

    pnData = (u32 *)(pabyDataBuffer + START_FLAG_OFFSET);
    *pnData = MESSAGE_PACKAGE_HEADER_START_FLAG;

    pnData = (u32 *)(pabyDataBuffer + INFO_SIZE_OFFSET);
    *pnData = PACKAGE_HEADER_SIZE;

    pnData = (u32 *)(pabyDataBuffer + DATA_CHECK_RESULT_OFFSET);
    if (ERRNO_SUCCESS !=
        xIPCDataCheckCalcResult(pabyDataBuffer, (*pnSize), &nCrcRet))
    {
        free(pabyDataBuffer);
        return ERRNO_FAIL;
    }
    *pnData = nCrcRet;

    pnData = (u32 *)(pabyDataBuffer + DATA_BYTE_CNT_OFFSET);
    *pnData = (*pnSize);

    pnData = (u32 *)(pabyDataBuffer + END_FLAG_OFFSET);
    *pnData = MESSAGE_PACKAGE_HEADER_END_FLAG;

    memcpy(pabyDataBuffer + DATA_BUFFER_BEGIN_OFFSET, pabyData, (*pnSize));

    *ppabyPack = pabyDataBuffer;
    *pnSize = (*pnSize) + PACKAGE_HEADER_SIZE;
    return ERRNO_SUCCESS;
}

EErrNo xIPCPackagePutPackMsg(u32 *pabyPack, u32 nSize)
{
    if (!pabyPack)
        return ERRNO_SUCCESS;

    free(pabyPack);

    return ERRNO_SUCCESS;
}


